package com.ebupt.migu.music.schedule.service;

import com.alibaba.fastjson.JSONObject;
import com.ebupt.migu.common.util.DateUtil;
import com.ebupt.migu.music.schedule.entity.Body;
import com.ebupt.migu.music.schedule.entity.MessageInfo;
import com.ebupt.migu.music.schedule.entity.UserSender;
import com.ebupt.migu.music.schedule.mapper.MessageNoticeTaskMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.HtmlUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author xuhongsong
 * @version 1.0
 * @date 2020/11/13 17:33
 */
@Component
@Slf4j
public class MessageNoticeService {


    @Value("${msg.appid}")
    private String MSG_APP_ID;
    @Value("${msg.account}")
    private String MSG_ACCOUNT;
    @Value("${msg.password}")
    private String MSG_PASSWORD;
    @Value("${msg.userip}")
    private String MSG_USER_IP;
    @Value("${msg.appkey}")
    private String MSG_APP_KEY;
    @Value("${msg.channelid}")
    private String MSG_CHANNEL_ID;
    @Value("${msg.url}")
    private String MSG_URL;
    @Value("${msg.cdn_server}")
    private String MSG_CDN_SERVER;


    private static MessageNoticeService messageNoticeService;

    @Autowired
    private MessageNoticeTaskMapper messageNoticeTaskMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Autowired
    private KafkaProducerService producerService;

    // 文件默认保存路径
    @Value("${path.file_rcode_path}")
    private String FILE_RECODE_PATH;

    /**
     * 用户信息
     */
    private final String _REDIS_KEY = "_user_info";

    private static String USER_CODE = "user_info_uid_";

    @PostConstruct
    public void init() {
        messageNoticeService = this;
        messageNoticeService.messageNoticeTaskMapper = this.messageNoticeTaskMapper;
    }

    public Body body(Map<String, Object> map, String uid, boolean isv_use) {
        Long start = System.currentTimeMillis();
        String msgNickName = map.get("msgNickName").toString();
        Map<String, Object> info = this.messageNoticeTaskMapper.queryMsgTypeInfo(msgNickName);
        Body body = new Body();
        if (null != map.get("msgText")) {
            body.setText(replaceUserData(isv_use, map.get("msgText").toString(), map.get("smsDefaultUsername").toString(), map.get("codeName").toString(), uid));
        }
        if (null != map.get("msgPic") && !"".equals(map.get("msgPic").toString())) {
            String msg_pic = map.get("msgPic").toString();
            try {
                body.setPic(URLEncoder.encode(msg_pic, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                log.error("pic's url encode error:{}", e.getMessage());
            }
        }
        if (null != map.get("msgLink")) {
            try {
                body.setLink(URLEncoder.encode(map.get("msgLink").toString(), "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                log.error("msg_link's url encode error:{}", e.getMessage());
            }
        }
        UserSender userSender = new UserSender();
        String icon = info.get("icon").toString();
        try {
            userSender.setIcon(URLEncoder.encode(icon, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            log.error("icon's url encode error:{}", e.getMessage());
        }
        userSender.setNickName(HtmlUtils.htmlEscape(msgNickName));
        body.setSender(userSender);
        log.info("构造body耗时:{}ms", System.currentTimeMillis() - start);
        return body;
    }


    public String replaceUserData(Boolean isvUse, String pushContent, String defaultUsername, String codeName, String uid) {
        String constructionJson = pushContent;
        if (isvUse) {
            try {
                //解析文件
                List<String> list = IOUtils.readLines(new FileInputStream(FILE_RECODE_PATH + codeName));
                Map hashMap = new HashMap<>();
                if (!list.isEmpty()) {
                    for (String i : list) {
                        String[] str = i.split(",|\\|");
                        String UID = str[0];
                        String CODE = str[1];
                        hashMap.put(UID, CODE);
                    }
                }
                log.info("是否使用千人千面：{}", isvUse);

                String userName = "";
                HashOperations hashOperations = redisTemplate.opsForHash();
                for (int i = 1; i < 81; i++) {
                    //如果有用户数据则替换
                    if (hashOperations.hasKey(USER_CODE + i, uid)) {
                        userName = String.valueOf(hashOperations.get(USER_CODE + i, uid));
                        break;
                    }
                }
                //如果没有影虎数据则使用默认值
                if (userName.isEmpty()) {
                    log.info("替换默认配置：{}", defaultUsername);
                    userName = defaultUsername.isEmpty() ? "" : defaultUsername;
                }
                log.info("");
                constructionJson = constructionJson.replaceAll("\\$username\\$", userName);
                if (!hashMap.isEmpty()) {
                    constructionJson = constructionJson.replaceAll("\\$redeemcode\\$", hashMap.get(uid).toString());

                }
                log.info("替换后的数据信息：{}", constructionJson);


            } catch (Exception e) {
                log.error("用户替换异常", e);
            }
        }
        return constructionJson;
    }

    /**
     * header authorization -用户验证信息
     *
     * @return
     */
    private String authorization() {
        // part1：   密码
        String password = MSG_PASSWORD;
        // part2：   6位随机码
        String nonce = getRandom();
        // part3：   created时间戳
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DateUtil.DATE_TIME_FORMAT_YYYYMMDDHHMISS);
        String created = simpleDateFormat.format(date);
        // 加密
        String password_base_64 = base_64_encode(sha_256(password + nonce + created));
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("Basicappid=\"");
        stringBuffer.append(MSG_APP_ID);
        stringBuffer.append("\",account=\"");
        stringBuffer.append(MSG_ACCOUNT);
        stringBuffer.append("\",password=\"");
        stringBuffer.append(password_base_64);
        stringBuffer.append("\",nonce=\"");
        stringBuffer.append(nonce);
        stringBuffer.append("\",created=\"");
        stringBuffer.append(created);
        stringBuffer.append("\",userip=\"");
        stringBuffer.append(MSG_USER_IP);
        stringBuffer.append("\",appkey=\"");
        stringBuffer.append(MSG_APP_KEY);
        stringBuffer.append("\",channelid=\"");
        stringBuffer.append(MSG_CHANNEL_ID);
        stringBuffer.append("\"");
        String auth = stringBuffer.toString();
        log.info("header authorization -用户验证信息:{}", auth);
        return auth;
    }

    /**
     * sha-256加密算法
     *
     * @param str
     * @return
     */
    public static byte[] sha_256(String str) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(str.getBytes());
            return messageDigest.digest();
        } catch (NoSuchAlgorithmException e) {
            log.error("SHA-256加密出错:{}", e.getMessage());
        }
        log.error("sha-256加密失败");
        return null;
    }

    /**
     * 获取6位长度随机数
     *
     * @return
     */
    public static String getRandom() {
        StringBuffer val = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            val.append(String.valueOf(random.nextInt(10)));
        }
        return val.toString();
    }

    /**
     * base64进行加密
     *
     * @return
     */
    private static String base_64_encode(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }

    /**
     * 构造消息通知xml结构
     *
     * @param uids
     * @return
     */
    public void cons_send_message(List<String> uids, Map<String, Object> strategy, String taskID) {
        boolean isv_use = "1".equals(strategy.get("isvUse").toString());
        String key_incr = strategy.get("strategyId") + "_" + DateUtil.getDateToday() + "_incr";
        if (isv_use && !uids.isEmpty()) {
            uids.forEach(uid -> {
                Body body_str = messageNoticeService.body(strategy, uid, isv_use);
                MessageInfo messageInfo = new MessageInfo();
                messageInfo.setType(0);
                messageInfo.setAction("11");
                messageInfo.setBody(body_str);
                messageInfo.setTaskId(taskID);
                messageInfo.setTargetID(uid);
                JSONObject params = new JSONObject();
                params.put("userID", "-1");
                params.put("messageInfo", messageInfo);
                producerService.sendMessage(strategy, MSG_URL, params.toJSONString(), key_incr, null);
                // doPost(MSG_URL, params.toJSONString());
                // redis_incr(key_incr);
            });
        } else {
            Body body_str = messageNoticeService.body(strategy, "", false);
            MessageInfo messageInfo = new MessageInfo();
            messageInfo.setType(0);
            messageInfo.setAction("11");
            messageInfo.setBody(body_str);
            messageInfo.setTaskId(taskID);
            JSONObject params = new JSONObject();
            params.put("userID", "-1");
            params.put("targetIDList", uids);
            params.put("messageInfo", messageInfo);
            JSONObject sendMessageReq = new JSONObject();
            sendMessageReq.put("sendMessageReq", params);

            producerService.sendMessage(strategy, MSG_URL, sendMessageReq.toJSONString(), key_incr, uids);
            // doPost(MSG_URL, sendMessageReq.toJSONString());
            //推送进度
            //for (int i = 0; i < uids.size(); i++) {
            //    redis_incr(key_incr);
            //}
        }
        // 短信下发进度保留3天，下发成功数/失败数保留7天
        //redisTemplate.expire(key_incr, 30, TimeUnit.DAYS);
    }

    /**
     * HTTP请求
     *
     * @param url
     * @param request
     * @return
     */
    private void doPost(String url, String request) {
        log.info("访问参数:{}", request);
        RestTemplate restTemplate = new RestTemplate();
        // 设置编码集
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", authorization());
        HttpEntity<String> entity = new HttpEntity<>(request, headers);
        HttpEntity httpEntity = restTemplate.postForEntity(url, entity, String.class);
        log.info(">>>>>>>>>>>>>>消息通知返回结果：{}", httpEntity.getBody());
    }

    /**
     * 原子自增
     *
     * @return
     */
    private void redis_incr(String key_name) {
        RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key_name, redisTemplate.getConnectionFactory());
        redisAtomicLong.getAndIncrement();
    }

}
